package com.eastdigit.bpm.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.ActivitiObjectNotFoundException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

import com.eastdigit.data.Constant;
import com.eastdigit.servlet.ReqBean;
import com.eastdigit.system.model.Constants;
import com.eastdigit.util.DateUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
 * Created by Administrator on 2015/9/21.
 */
@Service
public class ModelsService {
    @Autowired
    RepositoryService repositoryService;

    /**
     * 获取模型
     * 
     * @param reqBean
     * @return
     */
    public JSONObject getModels(ReqBean reqBean) {
        ModelQuery modelQuery = this.repositoryService.createModelQuery();
        if (reqBean.containsKey("id")) {
            modelQuery.modelId(reqBean.getInfo("id"));
        }

        if (reqBean.containsKey("category")) {
            modelQuery.modelCategory(reqBean.getInfo("category"));
        }

        if (reqBean.containsKey("name")) {
            modelQuery.modelName(reqBean.getInfo("name"));
        }

        if (reqBean.containsKey("processName")) {
            modelQuery.modelNameLike("%"+reqBean.getInfo("processName")+"%");
        }

        if (reqBean.containsKey("key")) {
            modelQuery.modelKey(reqBean.getInfo("key"));
        }
        modelQuery.orderByModelName().asc();
        int pageSize = Math.max(reqBean.getInfoInt(Constant.PAGE_SIZE), 10);
        int start = reqBean.getInfoInt(Constant.PAGE_INDEX) * pageSize;
        List<Model> list = modelQuery.listPage(start, pageSize);

        JSONArray array = new JSONArray();
        for (Model model : list) {
            JSONObject j = new JSONObject();
            j.put("id", model.getId());
            j.put("name", model.getName());
            j.put("key", model.getKey());
            j.put("category", model.getCategory());
            j.put("version", model.getVersion());
            j.put("metaInfo", model.getMetaInfo());
            j.put("createTime", DateUtil.formatDate(model.getCreateTime()));
            j.put("lastUpdateTime", DateUtil.formatDate(model.getLastUpdateTime()));
            array.add(j);
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("rows", array);
        jsonObject.put("total", modelQuery.count());

        return jsonObject;
    }

    /**
     * 创建模型
     * 
     * @param name
     * @param key
     * @param category
     * @param description
     * @throws UnsupportedEncodingException
     */
    public String create(String name, String key, String category, String description) throws UnsupportedEncodingException {
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode editorNode = objectMapper.createObjectNode();
        editorNode.put("id", "canvas");
        editorNode.put("resourceId", "canvas");
        ObjectNode stencilSetNode = objectMapper.createObjectNode();
        stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
        editorNode.put("stencilset", stencilSetNode);

        Model modelData = repositoryService.newModel();

        ObjectNode modelObjectNode = objectMapper.createObjectNode();
        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
        description = StringUtils.defaultString(description);
        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelData.setMetaInfo(modelObjectNode.toString());
        modelData.setName(name);
        modelData.setKey(StringUtils.defaultString(key));
        modelData.setCategory(category);

        repositoryService.saveModel(modelData);
        repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));
        return modelData.getId();
    }

    /**
     * 修改模型
     * 
     * @param modelId
     * @param name
     * @param key
     * @param category
     * @param description
     */
    public void updateModel(String modelId, String name, String key, String category, String description) {
        Model model = getModelFromRequest(modelId);
        if (category != null && !category.equals(model.getCategory())) {
            model.setCategory(category);
        }
        if (key == null) {
            key = "";
        }
        if (model.getKey() == null) {
            model.setKey("");
        }
        if (!model.getKey().equals(key)) {
            model.setKey(key);
        }

        if (!model.getName().equals(name)) {
            model.setName(name);
        }
        model.setVersion(model.getVersion() + 1);

        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode modelObjectNode = objectMapper.createObjectNode();
        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, model.getVersion());
        description = StringUtils.defaultString(description);
        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        model.setMetaInfo(modelObjectNode.toString());

        repositoryService.saveModel(model);
    }

    /**
     * 删除模型
     * 
     * @param modelId
     */
    public void deleteModel(String modelId) {
        Model model = getModelFromRequest(modelId);
        repositoryService.deleteModel(model.getId());
    }

    protected Model getModelFromRequest(String modelId) {
        Model model = repositoryService.createModelQuery().modelId(modelId).singleResult();

        if (model == null) {
            throw new ActivitiObjectNotFoundException("Could not find a model with id '" + modelId + "'.",
                    ProcessDefinition.class);
        }
        return model;
    }

    /**
     * 部署模型
     * 
     * @param modelId
     * @throws IOException
     */
    @CacheEvict(value = "processDefinition", allEntries = true)
    public void deploy(String modelId) throws IOException {
        Model modelData = repositoryService.getModel(modelId);
        ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService
                .getModelEditorSource(modelData.getId()));

        BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
        byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);

        String processName = modelData.getName() + ".bpmn20.xml";
        Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).category(modelData.getCategory())
                .addString(processName, new String(bpmnBytes, "utf-8")).deploy();
        modelData.setDeploymentId(deployment.getId());
        repositoryService.saveModel(modelData);
    }

    /**
     * 导入部署
     * 
     * @param fileUpload
     * @param request
     */
    public void importByFile(ReqBean reqBean) {
        if (reqBean != null) {
            String category = reqBean.getInfo("category");
            String modelFile = reqBean.getInfo("modelFile");
            try {
                String ATTACHMENT_PATH = Constants.ATTACHMENT_PATH;
                InputStream fileInputStream = new FileInputStream(ATTACHMENT_PATH + File.separator + modelFile);
                XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
                XMLStreamReader reader = xmlFactory.createXMLStreamReader(fileInputStream);
                BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(reader);
                if (bpmnModel.getMainProcess() != null || bpmnModel.getMainProcess().getId() != null) {
                    String processName = null;
                    if (StringUtils.isNotEmpty(bpmnModel.getMainProcess().getName())) {
                        processName = bpmnModel.getMainProcess().getName();
                    } else {
                        processName = bpmnModel.getMainProcess().getId();
                    }
                    Model modelData = repositoryService.newModel();
                    modelData.setCategory(category);
                    ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
                    modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processName);
                    modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
                    modelData.setMetaInfo(modelObjectNode.toString());
                    modelData.setName(processName);
                    String key = reqBean.getInfo("key");
                    if (key == null) {
                        modelData.setKey("");
                    } else {
                        modelData.setKey("key");
                    }
                    repositoryService.saveModel(modelData);

                    BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
                    ObjectNode editorNode = jsonConverter.convertToJson(bpmnModel);

                    repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}
